/**
 * @file STL_Text.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief
 * @version 0.1
 * @date 2020-09-15
 *
 * @copyright Copyright Sci-Tech Laboratories (c) 2020
 *
 */

#include "STL_Text.h"
#include <algorithm>
#include <iostream>
#include <netinet/in.h>  // htons, htonl, ntons, ntonl
#include <stdarg.h>  // va_start va_end
#include <stdlib.h>
#include <string>
#include <time.h>
namespace STL {

void STL_Text::seedRandom() {
    static bool init = false;
    if (!init) {
        struct timespec timestamp;
        clock_gettime(CLOCK_REALTIME, &timestamp);
        srand(timestamp.tv_nsec);
        init = true;
    }
}

std::string STL_Text::format(const char *format, ...) {
    // constexpr 是 C++11
    // 引入的关键字，用于声明一个常量表达式。常量表达式是在编译时就可以求值的表达式，这意味着它们可以在编译期间被计算，而不需要在运行时再进行计算
    static constexpr int bufferSize             = 1024 * 16;
    static thread_local char buffer[bufferSize] = { 0 };
    va_list args;
    va_start(args, format);  // 第二个参数是...之前的参数
    auto size = vsnprintf(buffer, bufferSize - 1, format, args);
    va_end(args);
    if (size < 0) {
        return "";  // 格式化错误处理
    }
    if (size >= bufferSize) {
        size = bufferSize - 1;  // 缓冲区溢出处理
    }
    buffer[size] = 0;
    return std::string(buffer);
}

std::string STL_Text::toUpperHex(std::string str, size_t offset, size_t max /* = 0*/) {
    std::string ret = "";
    char tempBuffer[4];
    for (std::size_t i = offset; i < str.length(); i++) {
        if (max > 0 && i - offset >= max)
            break;
        uint8_t temp = str.at(i);
        sprintf(tempBuffer, "%02X", temp);
        ret.append(std::string(tempBuffer));
    }
    return ret;
}

std::string STL_Text::toLowerHex(std::string str, size_t offset, size_t max /* = 0*/) {
    std::string ret = "";
    char tempBuffer[4];
    for (std::size_t i = offset; i < str.length(); i++) {
        if (max > 0 && i - offset >= max)
            break;
        uint8_t temp = str.at(i);
        sprintf(tempBuffer, "%02x", temp);
        ret.append(std::string(tempBuffer));
    }
    return ret;
}

void STL_Text::printHexCharPoint(uint8_t *data, size_t len) {
    for (int i = 0; i < (len < 20 ? len : 20); i++) {
        auto temp = data + i;
        printf("%d,%02x\n", *temp, *temp);
    }
}

std::string STL_Text::toHex(std::string str) {
    return toLowerHex(str, 0, 80);
}

std::string STL_Text::toHex(std::string str, size_t offset) {
    return toLowerHex(str, offset, 80);
}

/**
 * @brief 大端读取UInt16（即网络字节序）
 *
 * @param buffer
 * @param offset
 * @return uint16_t
 */
uint16_t STL_Text::readUInt16BE(std::string buffer, size_t offset) {
    if (buffer.size() < offset + 2)
        return 0;
    uint16_t buf1 = buffer.at(offset) & 0xFF;
    uint16_t buf2 = buffer.at(offset + 1) & 0xFF;
    return (buf1 << 8) + buf2;
}

bool STL_Text::string_start_with(const std::string &str, std::string prefix) {
    return (str.compare(0, prefix.size(), prefix) == 0);
}

bool STL_Text::string_end_with(const std::string &str, std::string suffix) {
    if (str.size() < suffix.size())
        return false;
    return (str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0);
}

/**
 * @brief 小端读取UInt16
 *
 * @param buffer
 * @param offset
 * @return uint16_t
 */
uint16_t STL_Text::readUInt16LE(std::string buffer, size_t offset) {
    if (buffer.size() < offset + 2)
        return 0;
    uint16_t buf1 = buffer.at(offset) & 0xFF;
    uint16_t buf2 = buffer.at(offset + 1) & 0xFF;
    return (buf2 << 8) + buf1;
}

std::string STL_Text::StringToHexString(std::string str) {
    std::string output;
    char temp[8];
    for (size_t i = 0; i < str.length(); ++i) {
        sprintf(temp, "%.2x", *(uint8_t *)(str.data() + i));
        output.append(temp, 2);
    }
    return output;
}

std::string STL_Text::HexStringtoString(std::string str) {
    std::string output;
    const char *pString = str.c_str();
    for (size_t i = 0; i < str.size(); i++) {
        if ((pString[i] >= '0' && pString[i] <= '9') || (pString[i] >= 'A' && pString[i] <= 'F')
            || (pString[i] >= 'a' && pString[i] <= 'f'))  // 属于0-9集合,返回是
        {
        } else {
            return "";
        }
    }
    for (size_t i = 0; i < str.length(); i += 2) {
        std::string str_temp = str.substr(i, 2);
        int temp             = std::stoi(str_temp, nullptr, 16);
        output.append(1, temp);
    }
    return output;
}

std::string STL_Text::trim(std::string str, std::string pattern /* = " "*/) {
    while (1) {
        if (str.empty())
            return str;
        std::string::size_type pos = str.find(pattern, 0);
        if (pos == 0) {
            str = str.substr(pattern.size());
        } else {
            break;
        }
    }
    while (1) {
        if (str.empty())
            return str;
        std::string::size_type pos = str.find(pattern, str.size() - pattern.size());
        if (pos == str.size() - pattern.size()) {
            str = str.substr(0, str.size() - pattern.size());
        } else {
            break;
        }
    }
    return str;
}

std::string STL_Text::strRemove(std::string str, char ch) {
    std::string return_str = "";
    int length             = (int)(str.length());
    for (int i = 0; i < length; i++)
        if (str[i] != ch)
            return_str += str[i];
    return return_str;
}

std::vector<std::string> STL_Text::split(std::string str, std::string pattern) {
    std::string::size_type pos;
    std::vector<std::string> result;
    if (str.empty())
        return result;
    str += pattern;
    size_t size = str.size();

    for (size_t i = 0; i < size; i++) {
        pos = str.find(pattern, i);
        if (pos < size) {
            std::string s = str.substr(i, pos - i);
            result.push_back(s);
            i = (int)(pos + pattern.size() - 1);
        }
    }

    return result;
}

std::string STL_Text::uint16ToNetworkString(STL::uint16 value) {
    std::string ret = "";
    value           = htons(value);
    ret.append(1, (value & 0xFF));
    ret.append(1, ((value >> 8) & 0xFF));
    return ret;
}

std::string STL_Text::uint32ToNetworkString(STL::uint32 value) {
    std::string ret = "";
    value           = htonl(value);
    ret.append(1, (value & 0xFF));
    ret.append(1, ((value >> 8) & 0xFF));
    ret.append(1, ((value >> 16) & 0xFF));
    ret.append(1, ((value >> 24) & 0xFF));
    return ret;
}

int STL_Text::uint16ToCharPtr(char *buf, uint16_t value) {
    if (buf == nullptr)
        return -1;
    value      = htons(value);
    *buf       = (value & 0xFF);
    *(buf + 1) = ((value >> 8) & 0xFF);
    return 0;
}

int STL_Text::uint32ToCharPtr(char *buf, uint32_t value) {
    if (buf == nullptr)
        return -1;
    value      = htonl(value);
    *buf       = (value & 0xFF);
    *(buf + 1) = ((value >> 8) & 0xFF);
    *(buf + 2) = ((value >> 16) & 0xFF);
    *(buf + 3) = ((value >> 24) & 0xFF);
    return 0;
}

STL::uint32 STL_Text::networkCharPointToUint32(char *buf, size_t offset) {
    std::string temp = std::string(buf + offset, 4);
    return networkStringPointToUint32(temp, 0);
}

STL::uint16 STL_Text::networkCharPointToUint16(char *buf, size_t offset) {
    std::string temp = std::string(buf + offset, 2);
    return networkStringPointToUint16(temp, 0);
}

STL::uint16 STL_Text::networkStringPointToUint16(std::string buf, size_t offset) {
    std::string subStr = buf.substr(offset, 4);
    STL::uint16 ret    = *(STL::uint16 *)(subStr.data());
    ret                = ntohs(ret);
    return ret;
}

STL::uint32 STL_Text::networkStringPointToUint32(std::string buf, size_t offset) {
    std::string subStr = buf.substr(offset, 4);
    STL::uint32 ret    = *(STL::uint32 *)(subStr.data());
    ret                = ntohl(ret);
    return ret;
}

std::string STL_Text::genNumberPassword(int len) {
    std::string ret;
    if (len < 1)
        len = 8;
    // srand((int)time(NULL));
    for (int i = 0; i < len; i++) {
        int value = rand() % 10 + 0x30;
        ret.append(1, value);
    }
    return ret;
};

std::string STL_Text::genCharacterAndNumberPassword(int len) {
    std::string ret;
    if (len < 1)
        len = 8;
    // srand((int)time(NULL));
    for (int i = 0; i < len; i++) {
        int value = rand() % 62 + 0x30;
        if (value > 0x39)
            value += 7;
        if (value > 0x5A)
            value += 6;
        ret.append(1, value);
    }
    return ret;
};

std::string STL_Text::toUpperStr(std::string str) {
    transform(str.begin(), str.end(), str.begin(), ::toupper);
    return str;
}

std::string STL_Text::toLowerStr(std::string str) {
    transform(str.begin(), str.end(), str.begin(), ::tolower);
    return str;
}

bool STL_Text::stringCompareIgnoreCase(std::string str1, std::string str2) {
    return (toLowerStr(str1) == toLowerStr(str2));
}

std::string STL_Text::addZero(int len, std::string value) {
    return addChar(len, value, '0');
}

std::string STL_Text::addChar(int len, std::string value, char c) {
    std::string ret = "";
    if (value.size() >= len)
        return value;
    size_t addLen = len - value.size();
    ret.append(addLen, c);
    ret.append(value);
    return ret;
}
s

    std::string
    STL_Text::string_format(const char *format, ...) {
#if 1  // 无长度限制
    va_list args;
    va_start(args, format);
    int count = vsnprintf(NULL, 0, format, args);
    va_end(args);

    va_start(args, format);
    char *buff = (char *)malloc((count + 1) * sizeof(char));
    vsnprintf(buff, (count + 1), format, args);
    va_end(args);

    std::string str(buff, count);
    free(buff);
    return str;

#else  // 最大长度限制：1024 - 1
    char buff[1024] = { 0 };
    va_list args;
    va_start(args, format);
    vsnprintf(buff, sizeof(buff), format, args);
    va_end(args);

    std::string str(buff);
    return str;
    ;
#endif
}

}  // namespace STL
